/*
 * =====================================================================================
 *
 *       Filename:  cl_client_socket.hxx
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  03/24/2011 12:42:55 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Ken Chen (Ken), chen_kenz@emc.com
 *        Company:  EMC
 *
 * =====================================================================================
 */

#ifndef _CL_CLIENT_SOCKET_HXX_
#define _CL_CLIENT_SOCKET_HXX_

#include <memory>
#include <functional>
#include <atomic>
#include "cl_socket.hxx"
#include "cl_net_callback.hxx"
#include "cl_common_defs.hxx"

namespace neo
{
class CLEventLooper;
class CLChannel;
class CLClientSocket: public CLSocket
{
public:
	typedef std::function<void (int connfd, CLSocketAddrUPtr serverAddr)> NewConnCallback;
	typedef std::function<void (void)> FailConnCallback;
	CLClientSocket(CLEventLooper* looper, 
			           const std::string& hostServer, 
								 int port, 
								 CLSocketType type);
  ~CLClientSocket();
	void setNewConnCallback(const NewConnCallback& cb);
	void setFailConnCallback(const FailConnCallback& cb);
	void connect(void);
	void reconnect(void);

private:
  enum State
	{
    SOCK_DISCONNECTED,
		SOCK_CONNECTING,
		SOCK_CONNECTED 
	};

private:
	void connectInLooper(void);
	void handleWrite(void);
  void handleError(void);
	void connecting(void);
	void removeChannel(void);
  void resetChannel(void);
	void retry(void);
	void setState(int state);

private:
	// 2 min
  const static int MAX_RETRY_DELAY = 2 * 60 * 1000;
  const static int INIT_RETRY_DELAY =  3000;

private:
  CLEventLooper* m_eventLooper;
	std::unique_ptr<CLChannel> m_connectChannel;
  NewConnCallback m_newConnCallback;
  FailConnCallback m_failConnCallback;
  std::atomic<int> m_curState;
  int m_retryDelay;
};

} // neo

#endif // _CL_CLIENT_SOCKET_HXX_

